Skip to content

feat: Event producer graph for graceful shutdown#165

Merged
chrisk314 merged 33 commits into
mainfrom
feat/producer-graph
Sep 14, 2025
Merged

feat: Event producer graph for graceful shutdown#165
chrisk314 merged 33 commits into
mainfrom
feat/producer-graph

Conversation

@chrisk314
Copy link
Copy Markdown
Contributor

@chrisk314 chrisk314 commented Aug 25, 2025

Summary

Closes #127 by introducing a component local event producer graph representation which is periodically updated for each component with the current status of other components which produce events of interest. For event driven models, the event producer graph will be updated throughout a model run - possibly only at the end after a long wait without input events. Once there are no more event producers in a component's local graph representation, the component will call close on its IOController, causing it to: process any final received events; and then shutdown in the next IO read cycle.

Changes

  • Adds dump method to IOController to track process event topology
  • Modifies Component.dump to include IOController dump
  • Adds get_process_for_component method to StateBackend implementations to retrieve process event topology within components
  • Adds new private attribute to Component to track state of other event producing components
  • Adds periodic check for status of event producing components
  • Modifies IOController close behaviour to wait some grace period for last events on close
  • Modifies Component IO read behaviour to close IOController when no more event producers in case of purely event driven scenario

@chrisk314 chrisk314 marked this pull request as draft August 25, 2025 10:12
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @chrisk314, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust mechanism for graceful shutdown within the system by implementing an event producer graph. This graph allows components to track the status of other components that produce events they consume. The changes also enhance the IOController's shutdown behavior, enabling it to wait for a grace period to ensure all pending events are processed before closing, directly addressing issue #127. This feature improves system stability and reliability during termination.

Highlights

  • Event Producer Graph: A new _event_producers attribute is added to the Component class to store a mapping of event types to the IDs of components producing those events. This graph is built during component initialization (_build_producer_graph) and periodically updated (_update_producer_graph) to reflect the current status of event-producing components.
  • Graceful Shutdown: The IOController's close method is modified to introduce a IO_CLOSE_GRACE_PERIOD. If there are still input events to process (excluding StopEvent), the controller will wait for this grace period before flushing its internal event buffer, allowing for last events to be processed.
  • State Backend Enhancements: New methods (get_process_for_component) are added to both StateBackend and SqliteStateBackend to efficiently retrieve the process data associated with a given component ID, which is crucial for building and updating the producer graph.
  • Component IO Information: The Component.dict() method now includes the io information from the IOController, making the component's input/output details available in its dictionary representation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an event producer graph to facilitate graceful shutdown of components, which is a solid approach. The changes are well-structured, including periodic updates to the graph and a grace period for event processing upon closing. My review includes a high-severity performance recommendation for fetching component statuses more efficiently, and a couple of medium-severity suggestions to improve code style and readability.

Comment thread plugboard/component/component.py
Comment thread plugboard/component/component.py Outdated
Comment thread plugboard/component/io_controller.py Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Sep 4, 2025

Benchmark comparison for bbfd6d1f (base) vs b038fd0f (PR)


--------------------------------------------------------------------------------------------------------------------- benchmark: 2 tests --------------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                   Max                  Mean            StdDev                Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     788.6491 (1.0)        801.0162 (1.0)        794.0621 (1.0)      4.5622 (1.07)       793.2954 (1.0)      5.3923 (1.0)           2;0  1.2593 (1.0)           5           1
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         994.6186 (1.26)     1,005.3568 (1.26)     1,000.6207 (1.26)     4.2764 (1.0)      1,000.0444 (1.26)     6.4592 (1.20)          2;0  0.9994 (0.79)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@chrisk314 chrisk314 marked this pull request as ready for review September 10, 2025 07:52
@github-actions
Copy link
Copy Markdown

Benchmark comparison for e597f924 (base) vs d2380d00 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         450.5699 (1.0)      458.2885 (1.0)      453.0436 (1.0)      3.0614 (1.0)      451.7786 (1.0)      3.0544 (1.0)           1;0  2.2073 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     796.8814 (1.77)     806.7054 (1.76)     799.9935 (1.77)     4.0029 (1.31)     798.4370 (1.77)     4.7911 (1.57)          1;0  1.2500 (0.57)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@github-actions
Copy link
Copy Markdown

Benchmark comparison for e597f924 (base) vs a08077d7 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests ------------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median                IQR            Outliers     OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         440.2511 (1.0)      451.0815 (1.0)      443.2220 (1.0)      4.5308 (1.0)      441.3414 (1.0)       4.6792 (1.0)           1;0  2.2562 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     792.5712 (1.80)     817.4556 (1.81)     801.3351 (1.81)     9.8997 (2.18)     800.9527 (1.81)     12.1147 (2.59)          1;0  1.2479 (0.55)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@codecov
Copy link
Copy Markdown

codecov Bot commented Sep 10, 2025

Codecov Report

❌ Patch coverage is 88.99083% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
plugboard/component/component.py 84.93% 6 Missing and 5 partials ⚠️
plugboard/component/io_controller.py 94.11% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread plugboard/component/component.py
@github-actions
Copy link
Copy Markdown

Benchmark comparison for e597f924 (base) vs ae264b58 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         438.2763 (1.0)      451.0489 (1.0)      443.9744 (1.0)      5.3462 (1.0)      444.2500 (1.0)      9.0382 (1.64)          2;0  2.2524 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     795.2666 (1.81)     811.8731 (1.80)     802.4462 (1.81)     5.9954 (1.12)     801.8323 (1.80)     5.5161 (1.0)           2;0  1.2462 (0.55)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@github-actions
Copy link
Copy Markdown

Benchmark comparison for e597f924 (base) vs c6b80c16 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         417.0330 (1.0)      420.3795 (1.0)      418.1893 (1.0)      1.4369 (1.0)      417.3808 (1.0)      2.1122 (1.0)           1;0  2.3913 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     757.7863 (1.82)     778.3057 (1.85)     767.6691 (1.84)     7.3850 (5.14)     768.2964 (1.84)     7.7277 (3.66)          2;0  1.3026 (0.54)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@github-actions
Copy link
Copy Markdown

Benchmark comparison for e597f924 (base) vs a5acd902 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.12-64bit/0001_pr)         432.4905 (1.0)      453.8243 (1.0)      441.9791 (1.0)      7.6793 (2.25)     440.5659 (1.0)      7.2003 (1.55)          2;0  2.2626 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.12-64bit/0001_base)     787.0336 (1.82)     796.0995 (1.75)     791.4081 (1.79)     3.4150 (1.0)      790.7638 (1.79)     4.6463 (1.0)           2;0  1.2636 (0.56)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

@chrisk314 chrisk314 merged commit b61d61e into main Sep 14, 2025
18 checks passed
@chrisk314 chrisk314 deleted the feat/producer-graph branch September 14, 2025 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Reliable mechanism for shutting down event driven models after processing of all events

2 participants